﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SocketProject
{
    public partial class Frm_TcpClient : Form
    {
        public enum MessageType
        {
            ASCII,
            UTF8,
            Hex,
            File,
            JSON
        }

        /*客户端程序编写步骤：
            第一步：调用socket()函数创建一个用于通信的套接字。
            第二步：通过设置套接字地址结构，说明客户端与之通信的服务器的IP地址和端口号。
            第三步：调用connect()函数来建立与服务器的连接，
            第四步：调用读写函数发送或者接收数据。
            第五步：终止连接。*/

        public Frm_TcpClient()
        {
            InitializeComponent();
            this.Load += Frm_TcpClient_Load;
        }

        private Socket socketClient;

        private void Frm_TcpClient_Load(object sender, EventArgs e)
        {
            this.lst_Rcv.Columns[1].Width = this.lst_Rcv.ClientSize.Width - this.lst_Rcv.Columns[0].Width;
        }

        private void LinkServer_Btn_Click(object sender, EventArgs e)
        {
            Addlog(0, "与服务器连接中");
            // 第一步：调用socket()函数创建一个用于通信的套接字。
            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // 第二步：通过设置套接字地址结构，说明客户端与之通信的服务器的IP地址和端口号。
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(this.ServerIp_txt.Text.Trim()), int.Parse(this.ServerPort_txt.Text));

            //第三步：调用connect()函数来建立与服务器的连接
            try
            {
                socketClient.Connect(ipe);
            }
            catch (Exception ex)
            {
                Addlog(2, "连接服务器失败" + ex.Message);
                return;
            }

            //创建一个监听线程
            Task.Run(new Action(() =>
            {
                CheckReceiveMsg();
            }));

            Addlog(0, "成功连接服务器");

            this.LinkServer_Btn.Enabled = false;
        }

        /// <summary>
        /// 多线程接收
        /// </summary>
        private void CheckReceiveMsg()
        {
            while (true)
            {
                //创建一个缓冲区
                byte[] buffer = new byte[1024 * 1024 * 10];

                int length = -1;
                // 第四步：调用读写函数发送或者接收数据。
                try
                {
                    length = socketClient.Receive(buffer);
                }
                catch (Exception)
                {
                    break;
                }

                if (length > 0)
                {
                    string msg = string.Empty;
                    MessageType type = (MessageType)buffer[0];
                    switch (type)
                    {
                        case MessageType.ASCII:
                            msg = Encoding.ASCII.GetString(buffer, 1, length - 1);
                            Addlog(0, "服务器" + ": " + msg);
                            break;

                        case MessageType.UTF8:
                            msg = Encoding.UTF8.GetString(buffer, 1, length - 1);
                            Addlog(0, "服务器: " + msg);
                            break;

                        case MessageType.Hex:
                            msg = HexGetString(buffer, 1, length - 1);
                            Addlog(0, " 服务器" + ": " + msg);

                            break;

                        case MessageType.File:
                            Invoke(new Action(() =>
                            {
                                SaveFileDialog sfd = new SaveFileDialog();
                                sfd.Filter = "txt files(*.txt)|*.txt|xls files(*.xls)|*.xls|xlsx files(*.xlsx)|*.xlsx|All files(*.*)|*.*";
                                if (sfd.ShowDialog() == DialogResult.OK)
                                {
                                    string fileSavePath = sfd.FileName;
                                    using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))
                                    {
                                        fs.Write(buffer, 1, length - 1);
                                    }
                                    Addlog(0, "文件成功保存至" + fileSavePath);
                                }
                            }));
                            break;

                        case MessageType.JSON:
                            Invoke(new Action(() =>
                            {
                                string res = Encoding.Default.GetString(buffer, 1, length);
                                List<Employee> employees = JSONHelper.JsonToEntity<List<Employee>>(res);
                                new Form1(employees).ShowDialog();
                            }));
                            break;

                        default:
                            break;
                    }

                    //string msg = Encoding.Default.GetString(buffer, 0, length);
                    //Addlog(0, "服务器:" + msg);
                }
                else
                {
                    break;
                }
            }
        }

        #region 接收信息的方法

        private string CurrentTime
        {
            get { return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); }
        }

        private void Addlog(int index, string info)
        {
            if (!this.lst_Rcv.InvokeRequired)
            {
                ListViewItem item = new ListViewItem("" + CurrentTime, index);
                item.SubItems.Add(info);
                lst_Rcv.Items.Insert(lst_Rcv.Items.Count, item);
            }
            else
            {
                Invoke(new Action(() =>
                {
                    ListViewItem item = new ListViewItem("" + CurrentTime, index);
                    item.SubItems.Add(info);
                    lst_Rcv.Items.Insert(lst_Rcv.Items.Count, item);
                }));
            }
        }

        #endregion 接收信息的方法

        private void Frm_TcpClient_FormClosing(object sender, FormClosingEventArgs e)
        {
            socketClient?.Close();
        }

        private void Btn_disConn_Click(object sender, EventArgs e)
        {
            socketClient?.Close();
            this.LinkServer_Btn.Enabled = true;
        }

        private void GroupSendSay_Btn_Click(object sender, EventArgs e)
        {
        }

        private void StartServer_Btn_Click(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// 发送ASCII
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SendASCII_Btn_Click(object sender, EventArgs e)
        {
            byte[] send = Encoding.ASCII.GetBytes((this.Sendtxt.Text.Trim()));

            //创建最终发送的数据
            byte[] sendMsg = new byte[send.Length + 1];

            //整体拷贝数组
            Array.Copy(send, 0, sendMsg, 1, send.Length);

            //给首字节赋值
            sendMsg[0] = (byte)MessageType.ASCII;

            socketClient?.Send(sendMsg);
            this.Sendtxt.Clear();
        }

        private void Btn_SendUTF8_Click(object sender, EventArgs e)
        {
            byte[] send = Encoding.UTF8.GetBytes((this.Sendtxt.Text.Trim()));

            //创建最终发送的数据
            byte[] sendMsg = new byte[send.Length + 1];

            //整体拷贝数组
            Array.Copy(send, 0, sendMsg, 1, send.Length);

            //给首字节赋值
            sendMsg[0] = (byte)MessageType.UTF8;

            socketClient?.Send(sendMsg);
            this.Sendtxt.Clear();
        }

        private void btn_SendHex_Click(object sender, EventArgs e)
        {
            byte[] send = Encoding.Default.GetBytes((this.Sendtxt.Text.Trim()));

            //创建最终发送的数据
            byte[] sendMsg = new byte[send.Length + 1];

            //整体拷贝数组
            Array.Copy(send, 0, sendMsg, 1, send.Length);

            //给首字节赋值
            sendMsg[0] = (byte)MessageType.Hex;

            socketClient?.Send(sendMsg);
            this.Sendtxt.Clear();
        }

        /// <summary>
        /// 选择文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SelectFile_Btn_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();

            //设置默认路径
            ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                this.SelectFile_txt.Text = ofd.FileName;
            }
        }

        private void SendFile_Btn_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(this.SelectFile_txt.Text))
            {
                MessageBox.Show("选文件!", "发送文件");
                return;
            }
            else
            {
                //发送两次
                using (FileStream fs = new FileStream(this.SelectFile_txt.Text, FileMode.Open))
                {
                    //文件名
                    string filename = Path.GetFileName(this.SelectFile_txt.Text);
                    //后缀名
                    string fileExtension = Path.GetExtension(this.SelectFile_txt.Text);
                    string strMsg = "文件：" + filename + "";
                    byte[] send1 = Encoding.UTF8.GetBytes(strMsg);
                    byte[] sendMsg = new byte[send1.Length + 1];
                    Array.Copy(send1, 0, sendMsg, 1, send1.Length);
                    sendMsg[0] = (byte)MessageType.UTF8;
                    socketClient?.Send(sendMsg);

                    //第二次发送文件内容
                    byte[] send2 = new byte[1024 * 1024 * 10];

                    int length = fs.Read(send2, 0, send2.Length);

                    byte[] send2msg = new byte[length + 1];

                    Array.Copy(send2, 0, send2msg, 1, length);
                    send2msg[0] = (byte)MessageType.File;

                    socketClient?.Send(send2msg);
                    this.SelectFile_txt.Clear();
                }
            }
        }

        private void btn_SendJson_Click(object sender, EventArgs e)
        {
            List<Employee> list = new List<Employee>()
            {
                new Employee()
                {
                    Id = 1,
                    Name = "Test2",
                    Level ="A",
                    Age = 22
                },
                new Employee()
                {
                    Id = 2,
                    Name = "Test1",
                    Level ="A",
                    Age = 26
                },
                new Employee()
                {
                    Id = 3,
                    Name = "Test4",
                    Level ="C",
                    Age = 22
                }
            };

            string str = JSONHelper.EntityToJSON(list);

            byte[] send = Encoding.Default.GetBytes(str);

            byte[] sendMsg = new byte[send.Length + 1];

            Array.Copy(send, 0, sendMsg, 1, send.Length);

            sendMsg[0] = (byte)MessageType.JSON;
            socketClient?.Send(sendMsg);
        }

        private string HexGetString(byte[] buffer, int start, int length)
        {
            string Result = string.Empty;
            if (buffer != null && buffer.Length >= start + length)
            {
                //截取字节数组
                Byte[] res = new Byte[length];
                Array.Copy(buffer, start, res, 0, length);

                string Hex = Encoding.Default.GetString(res, 0, res.Length);
                if (Hex.Contains(" "))
                {
                    string[] str = Regex.Split(Hex, "\\s+", RegexOptions.IgnoreCase);
                    foreach (var st in str)
                    {
                        Result += "0x" + st + "";
                    }
                }
                else
                {
                    Result += "0x" + Hex;
                }
            }
            else
            {
                Result = "Error";
            }
            return Result;
        }
    }
}